"""Support classes and functions for testing."""
import unittest as _unittest
import os as _os
import sys  as _sys
import warnings as _warnings


__all__ = ['unittest', 'imp', 'FileHelperTestCase']


import unittest
try:
    unittest.TestCase.assertRaisesRegex  # New in version 3.2 (previously assertRaisesRegexp).
except AttributeError:
    try:
        unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp  # New in version 2.7.
    except AttributeError:
        from tests.support_legacy import _TestCase
        unittest.TestCase = _TestCase


import imp
try:
    imp.reload  # New in version 3.2 (moved from built-ins).

    # Implement Brett Cannon's fix for issue 17358 - "imp.load_module()
    # leads to the improper caching of the 'file' argument".
    # See <http://bugs.python.org/issue17358>.
    def _load_source(name, pathname, file=None):
        msg = ('imp.load_source() is deprecated; use '
               'importlib.machinery.SourceFileLoader(name, pathname).load_module()'
               ' instead')
        _warnings.warn(msg, DeprecationWarning, 2)
        imp._LoadSourceCompatibility(name, pathname, file).load_module(name)
        module = _sys.modules[name]
        # To allow reloading to potentially work, use a non-hacked loader which
        # won't rely on a now-closed file object.
        module.__loader__ = imp._bootstrap.SourceFileLoader(name, pathname)
        return module

    def _load_compiled(name, pathname, file=None):
        msg = ('imp.load_compiled() is deprecated; use '
               'importlib.machinery.SourcelessFileLoader(name, pathname).'
               'load_module() instead ')
        _warnings.warn(msg, DeprecationWarning, 2)
        imp._LoadCompiledCompatibility(name, pathname, file).load_module(name)
        module = _sys.modules[name]
        # To allow reloading to potentially work, use a non-hacked loader which
        # won't rely on a now-closed file object.
        module.__loader__ = imp._bootstrap.SourcelessFileLoader(name, pathname)
        return module

    imp.load_source = _load_source
    imp.load_compiled = _load_compiled

except AttributeError:
    imp.reload = reload


import tempfile as _tempfile
try:
    _tempfile.TemporaryDirectory  # New in version 3.2.
except AttributeError:
    _template = 'tmp'

    class _TemporaryDirectory(object):
        def __init__(self, suffix='', prefix=_template, dir=None):
            self._closed = False
            self.name = None # Handle mkdtemp throwing an exception
            self.name = _tempfile.mkdtemp(suffix, prefix, dir)

        def __repr__(self):
            #return "<{} {!r}>".format(self.__class__.__name__, self.name)
            return '<%r %r>' % (self.__class__.__name__, self.name)

        def __enter__(self):
            return self.name

        def cleanup(self, _warn=False):
            if self.name and not self._closed:
                try:
                    self._rmtree(self.name)
                except (TypeError, AttributeError):
                    if 'None' not in str(ex):
                        raise
                    #print("ERROR: {!r} while cleaning up {!r}".format(ex, self,),
                    #    file=_sys.stderr)
                    msg = 'ERROR: %r while cleaning up %r\n%r' % (ex, self, _sys.stderr)
                    print(msg)

                    return
                self._closed = True
                if _warn:
                    self._warn('Implicitly cleaning up %r' % self,
                               ResourceWarning)

        def __exit__(self, exc, value, tb):
            self.cleanup()

        def __del__(self):
            self.cleanup(_warn=True)

        _listdir = staticmethod(_os.listdir)
        _path_join = staticmethod(_os.path.join)
        _isdir = staticmethod(_os.path.isdir)
        _islink = staticmethod(_os.path.islink)
        _remove = staticmethod(_os.remove)
        _rmdir = staticmethod(_os.rmdir)
        _os_error = _os.error
        _warn = _warnings.warn

        def _rmtree(self, path):
            for name in self._listdir(path):
                fullname = self._path_join(path, name)
                try:
                    isdir = self._isdir(fullname) and not self._islink(fullname)
                except self._os_error:
                    isdir = False
                if isdir:
                    self._rmtree(fullname)
                else:
                    try:
                        self._remove(fullname)
                    except self._os_error:
                        pass
            try:
                self._rmdir(path)
            except self._os_error:
                pass
    _tempfile.TemporaryDirectory = _TemporaryDirectory


class FileHelperTestCase(_unittest.TestCase):
    """TestCase with helpers for creating temporary files."""
    def setUp(self):
        self._original_cwd = _os.getcwd()
        self.tempdir = _tempfile.TemporaryDirectory()
        _os.chdir(self.tempdir.name)    # Change cwd.
        self._original_path = _sys.path
        _sys.path.insert(0, '.')         # Add cwd to sys.path.

    def tearDown(self):
        self.tempdir.cleanup()
        _os.chdir(self._original_cwd)   # Revert cwd.
        _sys.path = self._original_path  # Revert sys.path.

    def mkfile(self, fname, contents=None, time=None):
        dirname = _os.path.dirname(fname)
        if dirname and not _os.path.exists(dirname):
            _os.makedirs(dirname)

        f = None
        try:
            f = open(fname, 'w')
            if contents:
                f.write(contents)
        finally:
            if f:
                f.close()
        if time:
            _os.utime(fname, (time, time))
